package test

import java.io.{File, PrintWriter}
import java.security.MessageDigest
import java.sql.{Connection, PreparedStatement, ResultSet}
import java.time.LocalDateTime
import java.time.temporal.ChronoUnit
import java.util.StringTokenizer
import java.util.concurrent.TimeUnit

import com.typesafe.config.ConfigFactory
import org.apache.commons.codec.binary.Hex
import org.apache.commons.lang3.concurrent.Memoizer
import play.api.libs.json.Json

import scala.collection._
import scala.collection.JavaConverters._
import scala.concurrent.duration._
import scala.io.Source
import akka.actor.{Actor, ActorSystem, Cancellable, Props}
import akka.routing.RoundRobinPool
import cats.data.{EitherT, NonEmptyVector, OptionT, Reader, State, Validated, Writer, WriterT}
import javax.sql.DataSource
import org.h2.jdbcx.JdbcConnectionPool

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import sys.process._
import cats.{Applicative, Eval, Foldable, Functor, Monad, MonadError, Monoid, Semigroupal, Show, Traverse}
import implicits.Implicits._
import tool.Pojo.MyMessage

import scala.annotation.tailrec
import scala.util.Try

sealed trait Json

final case class JsObject(get: Map[String, Json]) extends Json

final case class JsString(get: String) extends Json

final case class JsNumber(get: Double) extends Json

case object JsNull extends Json

// The "serialize to JSON" behaviour is encoded in this trait
trait JsonWriter[A] {
  def write(value: A): Json
}

final case class Person(name: String, email: String)

object JsonWriterInstances {
  implicit val stringWriter: JsonWriter[String] =
    new JsonWriter[String] {
      def write(value: String): Json =
        JsString(value)
    }

  implicit val personWriter: JsonWriter[Person] =
    new JsonWriter[Person] {
      def write(value: Person): Json =
        JsObject(Map(
          "name" -> JsString(value.name),
          "email" -> JsString(value.email)
        ))
    }

  // etc...
}

object Json {
  def toJson[A](value: A)(implicit w: JsonWriter[A]): Json =
    w.write(value)
}

object JsonSyntax {

  implicit class JsonWriterOps[A](value: A) {
    def toJson(implicit w: JsonWriter[A]): Json =
      w.write(value)
  }

}

trait Printable[A] {
  def format(value: A): String
}

object PrintableInstances {

  implicit val stringPrint = new Printable[String] {
    override def format(value: String): String = {
      value.toString
    }
  }
  implicit val intPrint = new Printable[Int] {
    override def format(value: Int): String = {
      (value + 1).toString
    }
  }

  implicit val catPrint = new Printable[Cat] {
    override def format(c: Cat): String = {
      s"${c.name} is a ${c.age} year-old ${c.color} cat."
    }
  }

}

object Printable {
  def format[A](value: A)(implicit p: Printable[A]): String = {
    p.format(value)
  }

  def print[A](value: A)(implicit p: Printable[A]): Unit = {
    println(format(value))
  }
}

final case class Cat(name: String, age: Int, color: String)

object PrintableSyntax {

  implicit class PrintableOps[A](value: A) {
    def format(implicit p: Printable[A]): String = {
      p.format(value)
    }

    def print(implicit p: Printable[A]): Unit = {
      println(format)
    }

  }

}


/**
 * Created by Administrator on 2019/10/16
 */
object Learning1{

  def abs(n: Int): Int =
    if (n < 0) -n
    else n

  private def formatAbs(x: Int) = {
    val msg = "The absolute value of %d is %d"
    msg.format(x, abs(x))
  }

  def main(args: Array[String]): Unit = {
    import cats.instances.int._
    import cats.instances.string._
    import cats.instances.option._
    import cats.instances.vector._
    import cats.instances.list._
    import cats.instances.either._
    import cats.instances.future._
    import cats.instances.stream._
    import cats.Show
    import cats.Contravariant
    import cats.syntax.contravariant._
    import cats.syntax.semigroup._
    import cats.syntax.invariant._
    import cats.syntax.applicative._
    import cats.syntax.flatMap._
    import cats.syntax.functor._
    import cats.Monad
    import cats.Id
    import cats.syntax.either._
    import cats.MonadError
    import cats.syntax.applicative._
    import cats.syntax.applicativeError._
    import cats.syntax.monadError._
    import cats.instances.try_._
    import scala.language.higherKinds
    import cats.syntax.writer._
    import State._
    import cats.syntax.apply._
    import cats.syntax.semigroup._
    import cats.Monoid
    import cats.instances.int._
    import cats.instances.invariant._
    import cats.instances.list._
    import cats.instances.string._
    import cats.syntax.apply._
    import cats.syntax.validated._
    import cats.syntax.foldable._
    import cats.syntax.traverse._

    def factorial(n: Int): Int = {
      def go(n: Int, acc: Int): Int =
        if (n <= 0) acc
        else go(n-1, n*acc)
      go(n, 1)
    }

    def fib(n: Int): Int = {
      @annotation.tailrec
      def loop(n: Int, prev: Int, cur: Int): Int =
        if (n == 0) prev
        else loop(n - 1, cur, prev + cur)
      loop(n, 0, 1)
    }

    def findFirst(ss: Array[String], key: String): Int = {
      @annotation.tailrec
      def loop(n: Int): Int =
        if (n >= ss.length) -1
        else if (ss(n) == key) n
        else loop(n + 1)
      loop(0)
    }

//    def findFirst[A](as: Array[A], p: A => Boolean): Int = {
//      @annotation.tailrec
//      def loop(n: Int): Int =
//        if (n >= as.length) -1
//        else if (p(as(n))) n
//        else loop(n + 1)
//      loop(0)
//    }

//    def isSorted[A](as: Array[A], gt: (A,A) => Boolean): Boolean = {
//      @annotation.tailrec
//      def go(n: Int): Boolean =
//        if (n >= as.length-1) true
//        else if (gt(as(n), as(n+1))) false
//        else go(n+1)
//
//      go(0)
//    }

    println {
      //      val x = new StringBuilder("Hello")
      //      val y = x.append(", World")
      //      val r1 = y.toString
      //      val r2 = y.toString

      val x = new StringBuilder("Hello")
      val r1 = x.append(", World").toString
      val r2 = x.append(", World").toString
      (r1, r2)


    }
    println {
      val a = 15 + 2

    }
    println {
      List(1, 2, 3): Id[List[Int]]
    }
    println {
    }


  }
}
